import { useCallback, useContext } from "react";
import update from "immutability-helper";
import FunFormCtx, { genColumn, genRow } from "../../core";
import { WidgetConstructor } from "../../widgets";
import { message } from "antd";

type setPosition = { groupIndex: number; cardIndex: number; rowIndex: number };

const useRowSetting = () => {
  const { instance, updateInstance } = useContext(FunFormCtx);

  // 插入行
  const insertRow = useCallback(
    ({ groupIndex, cardIndex, rowIndex }: setPosition, type: 1 | 2) => {
      const newRow = genRow();
      updateInstance(
        update(instance, {
          groups: {
            [groupIndex]: {
              cards: {
                [cardIndex]: {
                  rows: {
                    $splice: [
                      [
                        type === 1 ? Math.max(rowIndex - 1, 0) : rowIndex + 1,
                        0,
                        newRow,
                      ],
                    ],
                  },
                },
              },
            },
          },
        })
      );
    },
    [instance, updateInstance]
  );

  // 删除行
  const deleteRow = useCallback(
    ({ groupIndex, cardIndex, rowIndex }: setPosition) => {
      updateInstance(
        update(instance, {
          groups: {
            [groupIndex]: {
              cards: {
                [cardIndex]: {
                  rows: (list) => {
                    if (list.length === 1) {
                      list.splice(rowIndex, 1, genRow());
                    } else {
                      list.splice(rowIndex, 1);
                    }
                    return list;
                  },
                },
              },
            },
          },
        })
      );
    },
    [instance, updateInstance]
  );

  // 更新行
  const updateRow = useCallback(
    (newRow: FunFormCardRow, position: setPosition) => {
      updateInstance(
        update(instance, {
          groups: {
            [position.groupIndex]: {
              cards: {
                [position.cardIndex]: {
                  rows: {
                    [position.rowIndex]: {
                      $set: newRow,
                    },
                  },
                },
              },
            },
          },
        })
      );
    },
    [instance, updateInstance]
  );

  // 插入列
  const insertCol = useCallback(
    (
      {
        groupIndex,
        cardIndex,
        colIndex,
      }: Omit<setPosition, "rowIndex"> & { colIndex: number },
      type: 1 | 2
    ) => {
      updateInstance(
        update(instance, {
          groups: {
            [groupIndex]: {
              cards: {
                [cardIndex]: {
                  labelWidths: (list) => {
                    list.splice(colIndex + 1, 0, list[colIndex]);
                    return list;
                  },
                  rows: (t) => {
                    return t.map((row) => {
                      if (row.columns.length === 0) return row;
                      const insertat = colIndex + 1;
                      // 判断当前插入行是否为强block
                      let el = row.columns[colIndex];
                      if (!el || !el.category) {
                        const at = row.columns.length - 1;
                        el = row.columns[at];
                      }
                      if (el.category?.allwaysFull) return row;
                      row.columns.splice(
                        type === 1 ? insertat - 1 : insertat,
                        0,
                        genColumn()
                      );
                      return row;
                    });
                  },
                },
              },
            },
          },
        })
      );
    },
    [instance, updateInstance]
  );

  // 删除列
  const deleteCol = useCallback(
    ({
      groupIndex,
      cardIndex,
      colIndex,
    }: Omit<setPosition, "rowIndex"> & { colIndex: number }) => {
      updateInstance(
        update(instance, {
          groups: {
            [groupIndex]: {
              cards: {
                [cardIndex]: {
                  labelWidths: (list) => {
                    list.splice(colIndex, 1);
                    return list;
                  },
                  rows: (t) => {
                    return t.map((orw) => {
                      const row = { ...orw };
                      if (row.columns.length === 0 || !row.columns[colIndex])
                        return row;
                      const { category } = row.columns[colIndex];
                      if (category && category.allwaysFull) {
                        row.columns = [];
                      } else {
                        row.columns.splice(colIndex, 1);
                        if (!row.columns.find((col) => !!col.category)) {
                          row.columns = [];
                        }
                      }
                      return row;
                    });
                  },
                },
              },
            },
          },
        })
      );
    },
    [instance, updateInstance]
  );

  const deleteColWidget = useCallback(
    ({
      groupIndex,
      cardIndex,
      rowIndex,
      colIndex,
    }: setPosition & { colIndex: number }) => {
      let tmp = update(instance, {
        groups: {
          [groupIndex]: {
            cards: {
              [cardIndex]: {
                rows: {
                  [rowIndex]: {
                    columns: {
                      [colIndex]: {
                        category: {
                          $set: undefined,
                        },
                        widget: {
                          $set: undefined,
                        },
                      },
                    },
                  },
                },
              },
            },
          },
        },
      });
      tmp = update(tmp, {
        groups: {
          [groupIndex]: {
            cards: {
              [cardIndex]: {
                rows: {
                  [rowIndex]: (orw) => {
                    const row = { ...orw };
                    let { colSpan } = row.columns[colIndex];
                    row.columns[colIndex].colSpan = 1;
                    const addList = [];
                    while (colSpan > 0) {
                      addList.push(genColumn());
                      colSpan--;
                    }
                    row.columns.splice(colIndex, 1, ...addList);
                    const isEmpty = row.columns.find((el) => el.category);
                    if (!isEmpty) row.columns = [];
                    return row;
                  },
                },
              },
            },
          },
        },
      });
      updateInstance(tmp);
    },
    [instance, updateInstance]
  );

  // 合并列
  const mergeColumn = useCallback(
    ({
      groupIndex,
      cardIndex,
      colIndex,
      rowIndex,
    }: setPosition & { colIndex: number }) => {
      updateInstance(
        update(instance, {
          groups: {
            [groupIndex]: {
              cards: {
                [cardIndex]: {
                  rows: {
                    [rowIndex]: (orw) => {
                      const row = { ...orw };
                      const next = row.columns[colIndex + 1];
                      if (!next || next.category) {
                        message.warning("合并失败");
                        return row;
                      }
                      const { colSpan } = row.columns[colIndex];
                      row.columns[colIndex].colSpan = colSpan + 1;
                      row.columns.splice(colIndex + 1, 1);
                      return row;
                    },
                  },
                },
              },
            },
          },
        })
      );
    },
    [instance, updateInstance]
  );
  // 取消合并
  const mergeCancel = useCallback(
    ({
      groupIndex,
      cardIndex,
      colIndex,
      rowIndex,
    }: setPosition & { colIndex: number }) => {
      updateInstance(
        update(instance, {
          groups: {
            [groupIndex]: {
              cards: {
                [cardIndex]: {
                  rows: {
                    [rowIndex]: (orw) => {
                      const row = { ...orw };
                      let { colSpan } = row.columns[colIndex];
                      row.columns[colIndex].colSpan = 1;
                      const addList = [];
                      while (colSpan > 1) {
                        addList.push(genColumn());
                        colSpan--;
                      }
                      row.columns.splice(colIndex + 1, 0, ...addList);
                      return row;
                    },
                  },
                },
              },
            },
          },
        })
      );
    },
    [instance, updateInstance]
  );
  // 分类创建行
  const createByCategory = useCallback(
    ({
      groupIndex,
      cardIndex,
      colIndex,
      rowIndex,
      category,
    }: setPosition & { colIndex: number; category: WidgetCategory }) => {
      updateInstance(
        update(instance, {
          groups: {
            [groupIndex]: {
              cards: {
                [cardIndex]: {
                  rows: {
                    [rowIndex]: {
                      columns: {
                        [colIndex]: {
                          category: {
                            $set: category,
                          },
                          widget: {
                            $set: WidgetConstructor(category),
                          },
                        },
                      },
                    },
                  },
                },
              },
            },
          },
        })
      );
    },
    [instance, updateInstance]
  );

  const catchById = useCallback(
    (uuid: string, groupIndex: number) => {
      // 只可能在一个区域里面移动
      // 找到被移动项的位置
      const cards = instance.groups[groupIndex].cards;
      let ele: FunFormCardColumn | undefined = undefined;
      for (let c = 0; c < cards.length; c++) {
        for (let r = 0; r < cards[c].rows.length; r++) {
          for (let col = 0; col < cards[c].rows[r].columns.length; col++) {
            if (cards[c].rows[r].columns[col].uuid === uuid) {
              ele = cards[c].rows[r].columns[col];
              return { ele, cardIndex: c, rowIndex: r, colIndex: col };
            }
          }
        }
      }
      return undefined;
    },
    [instance]
  );

  const moveColumnWidget = useCallback(
    (targetId: string, toId: string, groupIndex: number) => {
      const from = catchById(targetId, groupIndex);
      const to = catchById(toId, groupIndex);
      if (!from || !to) return;
      if (from.ele.category?.allwaysFull) return;
      let tmp = update(instance, {
        groups: {
          [groupIndex]: {
            cards: {
              [from.cardIndex]: {
                rows: {
                  [from.rowIndex]: {
                    columns: {
                      [from.colIndex]: {
                        category: {
                          $set: to.ele.category,
                        },
                        widget: {
                          $set: to.ele.widget,
                        },
                      },
                    },
                  },
                },
              },
            },
          },
        },
      });

      tmp = update(tmp, {
        groups: {
          [groupIndex]: {
            cards: {
              [to.cardIndex]: {
                rows: {
                  [to.rowIndex]: {
                    columns: {
                      [to.colIndex]: {
                        category: {
                          $set: from.ele.category,
                        },
                        widget: {
                          $set: from.ele.widget,
                        },
                      },
                    },
                  },
                },
              },
            },
          },
        },
      });

      tmp = update(tmp, {
        groups: {
          [groupIndex]: {
            cards: {
              [from.cardIndex]: {
                rows: {
                  [from.rowIndex]: (orw) => {
                    const row = { ...orw };
                    let { colSpan } = row.columns[from.colIndex];
                    row.columns[from.colIndex].colSpan = 1;
                    const addList = [];
                    while (colSpan > 0) {
                      addList.push(genColumn());
                      colSpan--;
                    }
                    row.columns.splice(from.colIndex, 1, ...addList);
                    const isEmpty = row.columns.find((el) => el.category);
                    if (!isEmpty) row.columns = [];
                    return row;
                  },
                },
              },
            },
          },
        },
      });

      updateInstance(tmp);
    },
    [catchById, instance, updateInstance]
  );

  const onWidgetMoveIn = useCallback(
    (widget: FunFormWidget, colId: string, to: setPosition, at: number) => {
      const from = catchById(colId, to.groupIndex);
      if (!from) return;
      const { defaultFull, allwaysFull } = from.ele.category as WidgetCategory;
      let columns: FunFormCardColumn[] = [];
      const len =
        instance.groups[to.groupIndex].cards[to.cardIndex].labelWidths.length;
      if (defaultFull || allwaysFull) {
        const newColumn = genColumn(from.ele.category, from.ele.widget);
        newColumn.colSpan = len;
        columns = [newColumn];
      } else
        columns = new Array(len).fill("").map((_, i) => {
          const columnTmp = genColumn();
          if (i === at) {
            columnTmp.category = widget.category;
            columnTmp.widget = widget;
          }
          return columnTmp;
        });

      const row =
        instance.groups[to.groupIndex].cards[to.cardIndex].rows[to.rowIndex];
      row.columns = columns;

      let tmp = update(instance, {
        groups: {
          [to.groupIndex]: {
            cards: {
              [from.cardIndex]: {
                rows: {
                  [from.rowIndex]: {
                    columns: {
                      [from.colIndex]: {
                        category: {
                          $set: undefined,
                        },
                        widget: {
                          $set: undefined,
                        },
                      },
                    },
                  },
                },
              },
            },
          },
        },
      });

      tmp = update(tmp, {
        groups: {
          [to.groupIndex]: {
            cards: {
              [to.cardIndex]: {
                rows: {
                  [to.rowIndex]: {
                    $set: row,
                  },
                },
              },
            },
          },
        },
      });

      tmp = update(tmp, {
        groups: {
          [to.groupIndex]: {
            cards: {
              [from.cardIndex]: {
                rows: {
                  [from.rowIndex]: {
                    columns: {
                      $apply(list: FunFormCardColumn[]) {
                        const isEmpty = list.find((el) => el.category);
                        if (!isEmpty) return [];
                        return list;
                      },
                    },
                  },
                },
              },
            },
          },
        },
      });

      updateInstance(tmp);
    },
    [catchById, instance, updateInstance]
  );

  return {
    insertRow,
    deleteRow,
    updateRow,
    insertCol,
    deleteCol,
    mergeCancel,
    mergeColumn,
    createByCategory,
    moveColumnWidget,
    onWidgetMoveIn,
    deleteColWidget,
  };
};

export default useRowSetting;
